// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package ssa

import (
	"cmd/compile/internal/logopt"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/obj/s390x"
	"cmd/internal/objabi"
	"cmd/internal/src"
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"math/bits"
	"os"
	"path/filepath"
)

type deadValueChoice bool

const (
	leaveDeadValues  deadValueChoice = false
	removeDeadValues                 = true
)

// deadcode指示重写是否应尝试删除任何已失效的值。
func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValueChoice) {
	// 重复重写，直到我们发现不再有重写
	pendingLines := f.cachedLineStarts // 保留需要移动到新值的语句边界/块
	pendingLines.clear()
	debug := f.pass.debug
	if debug > 1 {
		fmt.Printf("%s: rewriting for %s\n", f.pass.name, f.Name)
	}
	var iters int
	var states map[string]bool
	for {
		change := false
		for _, b := range f.Blocks {
			var b0 *Block
			if debug > 1 {
				b0 = new(Block)
				*b0 = *b
				b0.Succs = append([]Edge{}, b.Succs...) // 创建新副本，不使用别名
			}
			for i, c := range b.ControlValues() {
				for c.Op == OpCopy {
					c = c.Args[0]
					b.ReplaceControl(i, c)
				}
			}
			if rb(b) {
				change = true
				if debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", b0.LongString(), b.LongString())
				}
			}
			for j, v := range b.Values {
				var v0 *Value
				if debug > 1 {
					v0 = new(Value)
					*v0 = *v
					v0.Args = append([]*Value{}, v.Args...) // 创建新副本，不使用别名
				}
				if v.Uses == 0 && v.removeable() {
					if v.Op != OpInvalid && deadcode == removeDeadValues {
						// 重置所有现在未使用的值，所以我们减少了
						// 所有参数的使用计数。
						// 不完全是死码传递，因为它不处理循环。
						// 但它应该有助于使用==1规则触发。
						v.reset(OpInvalid)
						change = true
					}
					// 无点重写未使用的值。
					continue
				}

				vchange := phielimValue(v)
				if vchange && debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", v0.LongString(), v.LongString())
				}

				// 消除复制输入。
				// 如果任何副本输入未使用，请将其标记为无效并放弃其参数。对丢弃的参数递归地重复
				// 操作。
				// 此阶段有助于删除值的幻象“死拷贝”使用
				// 以便x.uses==1规则条件
				// 可靠地触发。
				for i, a := range v.Args {
					if a.Op != OpCopy {
						continue
					}
					aa := copySource(a)
					v.SetArg(i, aa)
					// 如果副本a有一个行边界指示符，尝试找到一个新值
					// 来保存它。第一个候选值是将替换a（aa）、
					// 的值，前提是它共享相同的块和线，并且符合条件。
					// 第二个选项是v，它的输入是a。因为aa在
					// 数据流中较早，所以它是更好的选择。
					if a.Pos.IsStmt() == src.PosIsStmt {
						if aa.Block == a.Block && aa.Pos.Line() == a.Pos.Line() && aa.Pos.IsStmt() != src.PosNotStmt {
							aa.Pos = aa.Pos.WithIsStmt()
						} else if v.Block == a.Block && v.Pos.Line() == a.Pos.Line() && v.Pos.IsStmt() != src.PosNotStmt {
							v.Pos = v.Pos.WithIsStmt()
						} else {
							// 在所有重写完成后，记录丢失的行并寻找新家。
							// TODO：同一个
							// 行的语句边界可能出现在多个块中，但只存储了一个块，因此，如果两个
							// 结尾都在这里，那么其中一个将丢失。
							pendingLines.set(a.Pos, int32(a.Block.ID))
						}
						a.Pos = a.Pos.WithNotStmt()
					}
					vchange = true
					for a.Uses == 0 {
						b := a.Args[0]
						a.reset(OpInvalid)
						a = b
					}
				}
				if vchange && debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", v0.LongString(), v.LongString())
				}

				// 应用重写函数
				if rv(v) {
					vchange = true
					// 如果值更改为语句边界的糟糕选择，请移动边界
					if v.Pos.IsStmt() == src.PosIsStmt {
						if k := nextGoodStatementIndex(v, j, b); k != j {
							v.Pos = v.Pos.WithNotStmt()
							b.Values[k].Pos = b.Values[k].Pos.WithIsStmt()
						}
					}
				}

				change = change || vchange
				if vchange && debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", v0.LongString(), v.LongString())
				}
			}
		}
		if !change {
			break
		}
		iters++
		if iters > 1000 || debug >= 2 {
			// 我们进行了大量可疑的重写（或者我们处于调试模式）。ABCFDG 
			// 开始检查循环。（这太贵了，无法常规进行。）我们找到了一个循环。
			if states == nil {
				states = make(map[string]bool)
			}
			h := f.rewriteHash()
			if _, ok := states[h]; ok {
				// 要对其进行诊断，请将debug设置为2，然后重新开始，
				// 这样我们将打印所有应用的规则，直到完成另一个周期。
				// 如果debug已经>=2，我们已经完成了，所以是时候崩溃了。
				if debug < 2 {
					debug = 2
					states = make(map[string]bool)
				} else {
					f.Fatalf("rewrite cycle detected")
				}
			}
			states[h] = true
		}
	}
	// 删除被删除的值
	for _, b := range f.Blocks {
		j := 0
		for i, v := range b.Values {
			vl := v.Pos
			if v.Op == OpInvalid {
				if v.Pos.IsStmt() == src.PosIsStmt {
					pendingLines.set(vl, int32(b.ID))
				}
				f.freeValue(v)
				continue
			}
			if v.Pos.IsStmt() != src.PosNotStmt && !notStmtBoundary(v.Op) && pendingLines.get(vl) == int32(b.ID) {
				pendingLines.remove(vl)
				v.Pos = v.Pos.WithIsStmt()
			}
			if i != j {
				b.Values[j] = v
			}
			j++
		}
		if pendingLines.get(b.Pos) == int32(b.ID) {
			b.Pos = b.Pos.WithIsStmt()
			pendingLines.remove(b.Pos)
		}
		b.truncateValues(j)
	}
}

// 从重写规则中调用的公共函数

func is64BitFloat(t *types.Type) bool {
	return t.Size() == 8 && t.IsFloat()
}

func is32BitFloat(t *types.Type) bool {
	return t.Size() == 4 && t.IsFloat()
}

func is64BitInt(t *types.Type) bool {
	return t.Size() == 8 && t.IsInteger()
}

func is32BitInt(t *types.Type) bool {
	return t.Size() == 4 && t.IsInteger()
}

func is16BitInt(t *types.Type) bool {
	return t.Size() == 2 && t.IsInteger()
}

func is8BitInt(t *types.Type) bool {
	return t.Size() == 1 && t.IsInteger()
}

func isPtr(t *types.Type) bool {
	return t.IsPtrShaped()
}

func isSigned(t *types.Type) bool {
	return t.IsSigned()
}

// mergeSym合并两个符号偏移量。
// 偏移量没有真正的合并，我们只选择非零的。
func mergeSym(x, y Sym) Sym {
	if x == nil {
		return y
	}
	if y == nil {
		return x
	}
	panic(fmt.Sprintf("mergeSym with two non-nil syms %v %v", x, y))
}

func canMergeSym(x, y Sym) bool {
	return x == nil || y == nil
}

// canMergeLoadClobber报告是否可以在不使计划无效的情况下将负载合并到目标中。
// 它还检查另一个非加载参数x是否符合我们的要求。
func canMergeLoadClobber(target, load, x *Value) bool {
	// 包含x的寄存器将被删除。
	// 如果我们仍然需要x的值，就不要合并。
	// 我们这里没有活性信息，但我们可以使用
	// 近似x死亡：
	// 1）目标是x的唯一用途。
	// 2）目标没有比x更深的循环。
	if x.Uses != 1 {
		return false
	}
	loopnest := x.Block.Func.loopnest()
	loopnest.calculateDepths()
	if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) {
		return false
	}
	return canMergeLoad(target, load)
}

// canMergeLoad报告是否可以将负载合并到目标，而不使计划无效。
func canMergeLoad(target, load *Value) bool {
	if target.Block.ID != load.Block.ID {
		// 如果加载在不同的块中，请不要将其合并。
		return false
	}

	// 如果加载
	// 有多个用途，则无法将加载合并到目标中。
	if load.Uses != 1 {
		return false
	}

	mem := load.MemoryArg()

	// 我们需要负载的内存arg在目标位置仍然有效。如果目标的某个参数依赖于load的内存参数的后继状态
	// 不可能是这种情况。
	// 则该
	// 
	// 例如，在
	// 中将加载合并到目标是无效的，因为newmem在到达目标之前杀死了oldmem 
	// 
	// 加载=读取。。。oldmem 
	// newmem=write。。。oldmem 
	// arg0=read。。。newmem 
	// target=add arg0 load 
	// 
	// 如果参数来自不同的块，那么我们可以立即排除
	// 它，因为它必须主导加载（在
	// 与目标相同的块）。
	var args []*Value
	for _, a := range target.Args {
		if a != load && a.Block.ID == target.Block.ID {
			args = append(args, a)
		}
	}

	// memPreds包含已知为load的
	// 内存状态的前辈的内存状态。它是惰性初始化的。
	var memPreds map[*Value]bool
	for i := 0; len(args) > 0; i++ {
		const limit = 100
		if i >= limit {
			// 如果我们做了很多迭代，就放弃。
			return false
		}
		v := args[len(args)-1]
		args = args[:len(args)-1]
		if target.Block.ID != v.Block.ID {
			// 由于目标和加载在同一块
			// 我们可以在离开块时停止搜索。
			continue
		}
		if v.Op == OpPhi {
			// 一个Phi意味着我们已经到达了街区的顶端。
			// 内存phi（如果存在）始终是块中的第一个逻辑存储。
			continue
		}
		if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
			// 我们可以处理这种情况，但它可能非常罕见。
			return false
		}
		if v.Op.SymEffect()&SymAddr != 0 {
			// 这种情况防止计算局部变量的
			// 地址的操作被迫将
			// 调度到相应的VarDef之前。
			// 见第28445期。
			// v1=加载。。。
			// v2=VARDEF 
			// v3=LEAQ 
			// v4=CMPQ v1 v3 
			// 我们不想将CMPQ与负载结合起来，因为这将迫使CMPQ在VARDEF之前调度，这反过来又要求LEAQ在VARDEF之前调度。
			return false
		}
		if v.Type.IsMemory() {
			if memPreds == nil {
				// 初始化包含内存状态的映射
				// 已知为load内存
				// 状态的前身。
				memPreds = make(map[*Value]bool)
				m := mem
				const limit = 50
				for i := 0; i < limit; i++ {
					if m.Op == OpPhi {
						// 内存phi（如果存在）始终是块中的第一个逻辑存储。
						break
					}
					if m.Block.ID != target.Block.ID {
						break
					}
					if !m.Type.IsMemory() {
						break
					}
					memPreds[m] = true
					if len(m.Args) == 0 {
						break
					}
					m = m.MemoryArg()
				}
			}

			// 如果v是mem的前身，我们可以合并。
			// 
			// 例如，我们可以在
			// 以下场景中将加载合并到目标中：
			// x=read。。。v 
			// mem=write。。。v 
			// 加载=读取。。。mem 
			// target=add x load 
			if memPreds[v] {
				continue
			}
			return false
		}
		if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
			// 如果v将mem作为输入，那么我们知道mem 
			// 此时有效。
			continue
		}
		for _, a := range v.Args {
			if target.Block.ID == a.Block.ID {
				args = append(args, a)
			}
		}
	}

	return true
}

// isSameCall报告sym是否与给定的命名符号相同
func isSameCall(sym interface{}, name string) bool {
	fn := sym.(*AuxCall).Fn
	return fn != nil && fn.String() == name
}

// canLoadUnaligned reports如果该架构支持未对齐的加载操作
func canLoadUnaligned(c *Config) bool {
	return c.ctxt.Arch.Alignment == 1
}

// nlz返回前导零的数量。
func nlz64(x int64) int { return bits.LeadingZeros64(uint64(x)) }
func nlz32(x int32) int { return bits.LeadingZeros32(uint32(x)) }
func nlz16(x int16) int { return bits.LeadingZeros16(uint16(x)) }
func nlz8(x int8) int   { return bits.LeadingZeros8(uint8(x)) }

// ntzX返回尾随零的数量。
func ntz64(x int64) int { return bits.TrailingZeros64(uint64(x)) }
func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
func ntz8(x int8) int   { return bits.TrailingZeros8(uint8(x)) }

func oneBit(x int64) bool   { return x&(x-1) == 0 && x != 0 }
func oneBit8(x int8) bool   { return x&(x-1) == 0 && x != 0 }
func oneBit16(x int16) bool { return x&(x-1) == 0 && x != 0 }
func oneBit32(x int32) bool { return x&(x-1) == 0 && x != 0 }
func oneBit64(x int64) bool { return x&(x-1) == 0 && x != 0 }

// nto返回尾随的数字。
func nto(x int64) int64 {
	return int64(ntz64(^x))
}

// logX返回n以2为底的对数。
// n必须是2的正幂（isPowerOfTwoX返回true）。
func log8(n int8) int64 {
	return int64(bits.Len8(uint8(n))) - 1
}
func log16(n int16) int64 {
	return int64(bits.Len16(uint16(n))) - 1
}
func log32(n int32) int64 {
	return int64(bits.Len32(uint32(n))) - 1
}
func log64(n int64) int64 {
	return int64(bits.Len64(uint64(n))) - 1
}

// log2uint32返回uint32（n）以2为底的对数，其中log2（0）=-1。
// 四舍五入。
func log2uint32(n int64) int64 {
	return int64(bits.Len32(uint32(n))) - 1
}

// isPowerOfTwo函数报告n是否为2的幂。
func isPowerOfTwo8(n int8) bool {
	return n > 0 && n&(n-1) == 0
}
func isPowerOfTwo16(n int16) bool {
	return n > 0 && n&(n-1) == 0
}
func isPowerOfTwo32(n int32) bool {
	return n > 0 && n&(n-1) == 0
}
func isPowerOfTwo64(n int64) bool {
	return n > 0 && n&(n-1) == 0
}

// isuint64 poweroftwo报告uint64（n）是否为2的幂。
func isUint64PowerOfTwo(in int64) bool {
	n := uint64(in)
	return n > 0 && n&(n-1) == 0
}

// isuint32 poweroftwo报告uint32（n）是否为2的幂。
func isUint32PowerOfTwo(in int64) bool {
	n := uint64(uint32(in))
	return n > 0 && n&(n-1) == 0
}

// is32位报告n是否可以表示为带符号的32位整数。
func is32Bit(n int64) bool {
	return n == int64(int32(n))
}

// is16Bit报告n是否可以表示为带符号的16位整数。
func is16Bit(n int64) bool {
	return n == int64(int16(n))
}

// is8Bit报告n是否可以表示为有符号8位整数。
func is8Bit(n int64) bool {
	return n == int64(int8(n))
}

// isU8Bit报告n是否可以表示为无符号8位整数。
func isU8Bit(n int64) bool {
	return n == int64(uint8(n))
}

// isU12Bit报告n是否可以表示为无符号12位整数。
func isU12Bit(n int64) bool {
	return 0 <= n && n < (1<<12)
}

// isU16Bit报告n是否可以表示为无符号16位整数。
func isU16Bit(n int64) bool {
	return n == int64(uint16(n))
}

// isU32Bit报告n是否可以表示为无符号32位整数。
func isU32Bit(n int64) bool {
	return n == int64(uint32(n))
}

// is20Bit报告n是否可以表示为带符号的20位整数。
func is20Bit(n int64) bool {
	return -(1<<19) <= n && n < (1<<19)
}

// b2i将布尔值转换为0或1以分配给生长素。
func b2i(b bool) int64 {
	if b {
		return 1
	}
	return 0
}

// b2i32将布尔值转换为0或1。
func b2i32(b bool) int32 {
	if b {
		return 1
	}
	return 0
}

// shiftIsBounded报告（左/右）移位值v是否已知有界。
// 如果移位小于移位值的宽度，则移位有界。
func shiftIsBounded(v *Value) bool {
	return v.AuxInt != 0
}

// 为了尽可能规范化
// 生成的代码，canonLessThan返回x是否“有序”小于y。
func canonLessThan(x, y *Value) bool {
	if x.Op != y.Op {
		return x.Op < y.Op
	}
	if !x.Pos.SameFileAndLine(y.Pos) {
		return x.Pos.Before(y.Pos)
	}
	return x.ID < y.ID
}

// truncate64Fto32F将float64值转换为float32，保留尾数的位模式
// 。如果截断导致信息丢失，它会惊慌失措。
func truncate64Fto32F(f float64) float32 {
	if !isExactFloat32(f) {
		panic("truncate64Fto32F: truncation is not exact")
	}
	if !math.IsNaN(f) {
		return float32(f)
	}
	// 转换过程中不一定会保留NaN位模式
	// 指令，因此我们需要手动进行转换。
	b := math.Float64bits(f)
	m := b & ((1 << 52) - 1) // 尾数（又称有效位）
	// /|符号|指数|尾数| 
	r := uint32(((b >> 32) & (1 << 31)) | 0x7f800000 | (m >> (52 - 23)))
	return math.Float32frombits(r)
}

// 扩展D2FTO64F将浮点32值转换为浮点64值，保留位
// 尾数模式。
func extend32Fto64F(f float32) float64 {
	if !math.IsNaN(float64(f)) {
		return float64(f)
	}
	// 转换过程中不一定会保留NaN位模式
	// 指令，因此我们需要手动进行转换。
	b := uint64(math.Float32bits(f))
	// /|符号|指数|尾数| 
	r := ((b << 32) & (1 << 63)) | (0x7ff << 52) | ((b & 0x7fffff) << (52 - 23))
	return math.Float64frombits(r)
}

// 部门需要修复报告部门是否需要修复代码。
func DivisionNeedsFixUp(v *Value) bool {
	return v.AuxInt == 0
}

// auxFrom64F对float64值进行编码，以便将其存储在生长素中。
func auxFrom64F(f float64) int64 {
	if f != f {
		panic("can't encode a NaN in AuxInt field")
	}
	return int64(math.Float64bits(f))
}

// auxFrom32F对float32值进行编码，以便将其存储在生长素中。
func auxFrom32F(f float32) int64 {
	if f != f {
		panic("can't encode a NaN in AuxInt field")
	}
	return int64(math.Float64bits(extend32Fto64F(f)))
}

// auxTo32F根据提供的生长素值对float32进行解码。
func auxTo32F(i int64) float32 {
	return truncate64Fto32F(math.Float64frombits(uint64(i)))
}

// auxTo64F根据提供的生长素值对浮点64进行解码。
func auxTo64F(i int64) float64 {
	return math.Float64frombits(uint64(i))
}

func auxIntToBool(i int64) bool {
	if i == 0 {
		return false
	}
	return true
}
func auxIntToInt8(i int64) int8 {
	return int8(i)
}
func auxIntToInt16(i int64) int16 {
	return int16(i)
}
func auxIntToInt32(i int64) int32 {
	return int32(i)
}
func auxIntToInt64(i int64) int64 {
	return i
}
func auxIntToUint8(i int64) uint8 {
	return uint8(i)
}
func auxIntToFloat32(i int64) float32 {
	return float32(math.Float64frombits(uint64(i)))
}
func auxIntToFloat64(i int64) float64 {
	return math.Float64frombits(uint64(i))
}
func auxIntToValAndOff(i int64) ValAndOff {
	return ValAndOff(i)
}
func auxIntToArm64BitField(i int64) arm64BitField {
	return arm64BitField(i)
}
func auxIntToInt128(x int64) int128 {
	if x != 0 {
		panic("nonzero int128 not allowed")
	}
	return 0
}
func auxIntToFlagConstant(x int64) flagConstant {
	return flagConstant(x)
}

func auxIntToOp(cc int64) Op {
	return Op(cc)
}

func boolToAuxInt(b bool) int64 {
	if b {
		return 1
	}
	return 0
}
func int8ToAuxInt(i int8) int64 {
	return int64(i)
}
func int16ToAuxInt(i int16) int64 {
	return int64(i)
}
func int32ToAuxInt(i int32) int64 {
	return int64(i)
}
func int64ToAuxInt(i int64) int64 {
	return int64(i)
}
func uint8ToAuxInt(i uint8) int64 {
	return int64(int8(i))
}
func float32ToAuxInt(f float32) int64 {
	return int64(math.Float64bits(float64(f)))
}
func float64ToAuxInt(f float64) int64 {
	return int64(math.Float64bits(f))
}
func valAndOffToAuxInt(v ValAndOff) int64 {
	return int64(v)
}
func arm64BitFieldToAuxInt(v arm64BitField) int64 {
	return int64(v)
}
func int128ToAuxInt(x int128) int64 {
	if x != 0 {
		panic("nonzero int128 not allowed")
	}
	return 0
}
func flagConstantToAuxInt(x flagConstant) int64 {
	return int64(x)
}

func opToAuxInt(o Op) int64 {
	return int64(o)
}

// Aux是一个以块和值的形式保存杂项数据的接口。
type Aux interface {
	CanBeAnSSAAux()
}

// stringAux包装字符串值，以便在Aux中使用。
type stringAux string

func (stringAux) CanBeAnSSAAux() {}

func auxToString(i Aux) string {
	return string(i.(stringAux))
}
func auxToSym(i Aux) Sym {
	// TODO:一种黑客行为-允许通过
	s, _ := i.(Sym)
	return s
}
func auxToType(i Aux) *types.Type {
	return i.(*types.Type)
}
func auxToCall(i Aux) *AuxCall {
	return i.(*AuxCall)
}
func auxToS390xCCMask(i Aux) s390x.CCMask {
	return i.(s390x.CCMask)
}
func auxToS390xRotateParams(i Aux) s390x.RotateParams {
	return i.(s390x.RotateParams)
}

func StringToAux(s string) Aux {
	return stringAux(s)
}
func symToAux(s Sym) Aux {
	return s
}
func callToAux(s *AuxCall) Aux {
	return s
}
func typeToAux(t *types.Type) Aux {
	return t
}
func s390xCCMaskToAux(c s390x.CCMask) Aux {
	return c
}
func s390xRotateParamsToAux(r s390x.RotateParams) Aux {
	return r
}

// uaddOvf报告未签名的a+b是否会溢出。
func uaddOvf(a, b int64) bool {
	return uint64(a)+uint64(b) < uint64(a)
}

// loadLSymOffset模拟将偏移量处的单词读入只读符号的运行时内存。如果它将读取指向
// 另一个符号的指针，则返回该符号。否则，它返回nil。
func loadLSymOffset(lsym *obj.LSym, offset int64) *obj.LSym {
	if lsym.Type != objabi.SRODATA {
		return nil
	}

	for _, r := range lsym.R {
		if int64(r.Off) == offset && r.Type&^objabi.R_WEAK == objabi.R_ADDR && r.Add == 0 {
			return r.Sym
		}
	}

	return nil
}

// 反虚拟化中间调用
// /'sym'是itab 
func devirtLESym(v *Value, aux Aux, sym Sym, offset int64) *obj.LSym {
	n, ok := sym.(*obj.LSym)
	if !ok {
		return nil
	}

	lsym := loadLSymOffset(n, offset)
	if f := v.Block.Func; f.pass.debug > 0 {
		if lsym != nil {
			f.Warnl(v.Pos, "de-virtualizing call")
		} else {
			f.Warnl(v.Pos, "couldn't de-virtualize call")
		}
	}
	return lsym
}

func devirtLECall(v *Value, sym *obj.LSym) *Value {
	v.Op = OpStaticLECall
	auxcall := v.Aux.(*AuxCall)
	auxcall.Fn = sym
	// 删除第一个参数
	v.Args[0].Uses--
	copy(v.Args[0:], v.Args[1:])
	v.Args[len(v.Args)-1] = nil // aid GC 
	v.Args = v.Args[:len(v.Args)-1]
	return v
}

// isSamePtr报告p1和p2是否指向同一地址。
func isSamePtr(p1, p2 *Value) bool {
	if p1 == p2 {
		return true
	}
	if p1.Op != p2.Op {
		return false
	}
	switch p1.Op {
	case OpOffPtr:
		return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
	case OpAddr, OpLocalAddr:
		// OpAddr的第0个参数是OpSP或OpSB，这意味着它是由其Op唯一标识的。
		// 只有在[z]cse运行后，才可以检查值是否相等。
		return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
	case OpAddPtr:
		return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
	}
	return false
}

func isStackPtr(v *Value) bool {
	for v.Op == OpOffPtr || v.Op == OpAddPtr {
		v = v.Args[0]
	}
	return v.Op == OpSP || v.Op == OpLocalAddr
}

// 不相交报告[p1:p1+n1）
// 指定的内存区域是否与[p2:p2+n2）.返回值false并不意味着区域重叠。p1和p2不一样，如果它们都是opaddr，那么它们指向不同的变量。如果一个指针在堆栈上，另一个是参数
func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
	if n1 == 0 || n2 == 0 {
		return true
	}
	if p1 == p2 {
		return false
	}
	baseAndOffset := func(ptr *Value) (base *Value, offset int64) {
		base, offset = ptr, 0
		for base.Op == OpOffPtr {
			offset += base.AuxInt
			base = base.Args[0]
		}
		return base, offset
	}
	p1, off1 := baseAndOffset(p1)
	p2, off2 := baseAndOffset(p2)
	if isSamePtr(p1, p2) {
		return !overlap(off1, n1, off2, n2)
	}
	// 那么它们就不能重叠。
	switch p1.Op {
	case OpAddr, OpLocalAddr:
		if p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpSP {
			return true
		}
		return (p2.Op == OpArg || p2.Op == OpArgIntReg) && p1.Args[0].Op == OpSP
	case OpArg, OpArgIntReg:
		if p2.Op == OpSP || p2.Op == OpLocalAddr {
			return true
		}
	case OpSP:
		return p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpArg || p2.Op == OpArgIntReg || p2.Op == OpSP
	}
	return false
}

// moveSize返回t对齐MOV指令移动的字节数
func moveSize(align int64, c *Config) int64 {
	switch {
	case align%8 == 0 && c.PtrSize == 8:
		return 8
	case align%4 == 0:
		return 4
	case align%2 == 0:
		return 2
	}
	return 1
}

// 合并点在a的块中找到一个控制b的块，它本身就是
// 由a的所有块控制。如果找不到，则返回nil。
// 即使存在，也可能返回nil。
func mergePoint(b *Block, a ...*Value) *Block {
	// 从b向后走，寻找a的一个街区。

	// 最大距离
	d := 100

	for d > 0 {
		for _, x := range a {
			if b == x.Block {
				goto found
			}
		}
		if len(b.Preds) > 1 {
			// 不知道该走哪条路回去。中止
			return nil
		}
		b = b.Preds[0].b
		d--
	}
	return nil // 太远了
found:
	// 此时，r是我们通过向后走找到的a中的第一个值。
	// 如果我们退货，r就是了。
	r := b

	// 继续，数一数我们找到的其他a。他们一定都主宰了r.
	na := 0
	for d > 0 {
		for _, x := range a {
			if b == x.Block {
				na++
			}
		}
		if na == len(a) {
			// 在一次倒退中发现了所有的a。我们可以返回r.
			return r
		}
		if len(b.Preds) > 1 {
			return nil
		}
		b = b.Preds[0].b
		d--

	}
	return nil // 太远
}

// clobber使值无效。返回true。
// clobber被重写规则用来：
// A）确保这些值真的已经死了，不再使用。
// B）递减使用值参数的计数。
func clobber(vv ...*Value) bool {
	for _, v := range vv {
		v.reset(OpInvalid)
		// 注意：保持v.块完好无损。Block字段在clobber之后使用。
	}
	return true
}

// clobberIfDead在使用计数为1时重置v。返回true。
// 重写规则使用clobberIfDead来减少
// 当v已死亡且从未使用时，使用v的参数计数。
func clobberIfDead(v *Value) bool {
	if v.Uses == 1 {
		v.reset(OpInvalid)
	}
	// 注意：保持v.块完好无损。Block字段在ClobberRifDead之后使用。
	return true
}

// noteRule是一种在编写新规则时跟踪规则是否匹配的简单方法。使兴趣规则也以
// noteRule（“自我提示：兴趣规则匹配”）
// 为条件，并且当规则匹配时，将打印该消息。
func noteRule(s string) bool {
	fmt.Println(s)
	return true
}

// countRule递增函数。规则匹配[key]。
// If Func。ruleMatches在编译
// 结束时为非零，它将被打印到标准输出。
// 这是为了在开发新规则时更容易找到包含大量规则匹配的函数。
func countRule(v *Value, key string) bool {
	f := v.Block.Func
	if f.ruleMatches == nil {
		f.ruleMatches = make(map[string]int)
	}
	f.ruleMatches[key]++
	return true
}

// 警告规则在
// v不在自动生成的代码中、cond为true且规则已触发时，生成带字符串s的编译器调试输出。
func warnRule(cond bool, v *Value, s string) bool {
	if pos := v.Pos; pos.Line() > 1 && cond {
		v.Block.Func.Warnl(pos, s)
	}
	return true
}

// 对于伪op-like（小于x），extract x 
func flagArg(v *Value) *Value {
	if len(v.Args) != 1 || !v.Args[0].Type.IsFlags() {
		return nil
	}
	return v.Args[0]
}

// arm64Negate查找ARM64条件代码的补码，例如
// 等等！相等->不相等或！LessThan->GreaterEqual 
// 
// 对于浮点，它更微妙，因为NaN是无序的。我们做
// /！LessThanF->NotLessThanF，后者负责照顾NaNs。
func arm64Negate(op Op) Op {
	switch op {
	case OpARM64LessThan:
		return OpARM64GreaterEqual
	case OpARM64LessThanU:
		return OpARM64GreaterEqualU
	case OpARM64GreaterThan:
		return OpARM64LessEqual
	case OpARM64GreaterThanU:
		return OpARM64LessEqualU
	case OpARM64LessEqual:
		return OpARM64GreaterThan
	case OpARM64LessEqualU:
		return OpARM64GreaterThanU
	case OpARM64GreaterEqual:
		return OpARM64LessThan
	case OpARM64GreaterEqualU:
		return OpARM64LessThanU
	case OpARM64Equal:
		return OpARM64NotEqual
	case OpARM64NotEqual:
		return OpARM64Equal
	case OpARM64LessThanF:
		return OpARM64NotLessThanF
	case OpARM64NotLessThanF:
		return OpARM64LessThanF
	case OpARM64LessEqualF:
		return OpARM64NotLessEqualF
	case OpARM64NotLessEqualF:
		return OpARM64LessEqualF
	case OpARM64GreaterThanF:
		return OpARM64NotGreaterThanF
	case OpARM64NotGreaterThanF:
		return OpARM64GreaterThanF
	case OpARM64GreaterEqualF:
		return OpARM64NotGreaterEqualF
	case OpARM64NotGreaterEqualF:
		return OpARM64GreaterEqualF
	default:
		panic("unreachable")
	}
}

// ARM64Inverte求值（InvertFlags op），这与更改条件代码相同，例如
// 如果参数
// 与标志生成指令相反，例如
// （反转标志（CMP x y））->（CMP y x）
func arm64Invert(op Op) Op {
	switch op {
	case OpARM64LessThan:
		return OpARM64GreaterThan
	case OpARM64LessThanU:
		return OpARM64GreaterThanU
	case OpARM64GreaterThan:
		return OpARM64LessThan
	case OpARM64GreaterThanU:
		return OpARM64LessThanU
	case OpARM64LessEqual:
		return OpARM64GreaterEqual
	case OpARM64LessEqualU:
		return OpARM64GreaterEqualU
	case OpARM64GreaterEqual:
		return OpARM64LessEqual
	case OpARM64GreaterEqualU:
		return OpARM64LessEqualU
	case OpARM64Equal, OpARM64NotEqual:
		return op
	case OpARM64LessThanF:
		return OpARM64GreaterThanF
	case OpARM64GreaterThanF:
		return OpARM64LessThanF
	case OpARM64LessEqualF:
		return OpARM64GreaterEqualF
	case OpARM64GreaterEqualF:
		return OpARM64LessEqualF
	case OpARM64NotLessThanF:
		return OpARM64NotGreaterThanF
	case OpARM64NotGreaterThanF:
		return OpARM64NotLessThanF
	case OpARM64NotLessEqualF:
		return OpARM64NotGreaterEqualF
	case OpARM64NotGreaterEqualF:
		return OpARM64NotLessEqualF
	default:
		panic("unreachable")
	}
}

// 根据可能恒定的标志值
// 评估ARM64 op；返回1表示真，返回
// /-1表示假，返回0表示非常数。
func ccARM64Eval(op Op, flags *Value) int {
	fop := flags.Op
	if fop == OpARM64InvertFlags {
		return -ccARM64Eval(op, flags.Args[0])
	}
	if fop != OpARM64FlagConstant {
		return 0
	}
	fc := flagConstant(flags.AuxInt)
	b2i := func(b bool) int {
		if b {
			return 1
		}
		return -1
	}
	switch op {
	case OpARM64Equal:
		return b2i(fc.eq())
	case OpARM64NotEqual:
		return b2i(fc.ne())
	case OpARM64LessThan:
		return b2i(fc.lt())
	case OpARM64LessThanU:
		return b2i(fc.ult())
	case OpARM64GreaterThan:
		return b2i(fc.gt())
	case OpARM64GreaterThanU:
		return b2i(fc.ugt())
	case OpARM64LessEqual:
		return b2i(fc.le())
	case OpARM64LessEqualU:
		return b2i(fc.ule())
	case OpARM64GreaterEqual:
		return b2i(fc.ge())
	case OpARM64GreaterEqualU:
		return b2i(fc.uge())
	}
	return 0
}

// 日志规则记录规则的使用。只有在使用-log选项生成了
// 重写规则时，才会启用此功能，请参见gen/rulegen。去
func logRule(s string) {
	if ruleFile == nil {
		// 打开一个日志文件以写入日志。我们在append 
		// 模式下打开，因为所有。bash多次运行编译器，
		// 我们想要所有这些日志的串联。当然，这意味着用户需要使用旧的日志来获取新的数据。
		// 待办事项：全部。bash并行运行编译器。需要以某种方式同步日志记录吗？
		w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
			os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			panic(err)
		}
		ruleFile = w
	}
	_, err := fmt.Fprintln(ruleFile, s)
	if err != nil {
		panic(err)
	}
}

var ruleFile io.Writer

func min(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}

func isConstZero(v *Value) bool {
	switch v.Op {
	case OpConstNil:
		return true
	case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConst32F, OpConst64F:
		return v.AuxInt == 0
	}
	return false
}

// reciprocalExact64报告1/c是否完全可代表。
func reciprocalExact64(c float64) bool {
	b := math.Float64bits(c)
	man := b & (1<<52 - 1)
	if man != 0 {
		return false // 不是2的幂，非规范或NaN 
	}
	exp := b >> 52 & (1<<11 - 1)
	// 指数偏差为0x3ff。因此，取一个数的倒数将指数改为0x7fe-exp。倒数报告1/c是否完全可代表。
	switch exp {
	case 0:
	case 0x7ff:
	case 0x7fe:
	default:
		return true
	}
}

func reciprocalExact32(c float32) bool {
	b := math.Float32bits(c)
	man := b & (1<<23 - 1)
	if man != 0 {
		return false // 不是2的幂，非规范或NaN 
	}
	exp := b >> 23 & (1<<8 - 1)
	// 指数偏差为0x7f。因此，取一个数的倒数将指数改为0xfe-exp。
	switch exp {
	case 0:
		return false // /±0 
	case 0xff:
		return false // /±inf 
	case 0xfe:
		return false // 指数不可表示
	default:
		return true
	}
}

// 检查一个立即数是否可以直接编码到ARM指令
func isARMImmRot(v uint32) bool {
	for i := 0; i < 16; i++ {
		if v&^0xff == 0 {
			return true
		}
		v = v<<2 | v>>30
	}

	return false
}

// 报告给定偏移量和
// 大小对重叠。
func overlap(offset1, size1, offset2, size2 int64) bool {
	if offset1 >= offset2 && offset2+size2 > offset1 {
		return true
	}
	if offset2 >= offset1 && offset1+size1 > offset2 {
		return true
	}
	return false
}

func areAdjacentOffsets(off1, off2, size int64) bool {
	return off1+size == off2 || off1 == off2+size
}

// 检查值是否将64位寄存器的上32位置零。
// 深度限制递归深度。在AMD64中。规则3被用作限制，
// 因为它捕获的案例数量与规则4相同。
func zeroUpper32Bits(x *Value, depth int) bool {
	switch x.Op {
	case OpAMD64MOVLconst, OpAMD64MOVLload, OpAMD64MOVLQZX, OpAMD64MOVLloadidx1,
		OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVBload, OpAMD64MOVBloadidx1,
		OpAMD64MOVLloadidx4, OpAMD64ADDLload, OpAMD64SUBLload, OpAMD64ANDLload,
		OpAMD64ORLload, OpAMD64XORLload, OpAMD64CVTTSD2SL,
		OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst,
		OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst,
		OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL,
		OpAMD64SHRL, OpAMD64SHRLconst, OpAMD64SARL, OpAMD64SARLconst,
		OpAMD64SHLL, OpAMD64SHLLconst:
		return true
	case OpArg:
		return x.Type.Size() == 4
	case OpPhi, OpSelect0, OpSelect1:
		// Phis可以将彼此用作参数，而不是跟踪访问值，
		// 只需限制递归深度即可。
		if depth <= 0 {
			return false
		}
		for i := range x.Args {
			if !zeroUpper32Bits(x.Args[i], depth-1) {
				return false
			}
		}
		return true

	}
	return false
}

// ZeroUpper48位类似于ZeroUpper32位，但对于高48位
func zeroUpper48Bits(x *Value, depth int) bool {
	switch x.Op {
	case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2:
		return true
	case OpArg:
		return x.Type.Size() == 2
	case OpPhi, OpSelect0, OpSelect1:
		// Phis可以将彼此用作参数，而不是跟踪访问值，
		// 只限制递归深度。
		if depth <= 0 {
			return false
		}
		for i := range x.Args {
			if !zeroUpper48Bits(x.Args[i], depth-1) {
				return false
			}
		}
		return true

	}
	return false
}

// ZeroUpper56位类似于ZeroUpper32位，但对于较高的56位
func zeroUpper56Bits(x *Value, depth int) bool {
	switch x.Op {
	case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1:
		return true
	case OpArg:
		return x.Type.Size() == 1
	case OpPhi, OpSelect0, OpSelect1:
		// Phis可以将彼此用作参数，而不是跟踪访问值，
		// 只限制递归深度。
		if depth <= 0 {
			return false
		}
		for i := range x.Args {
			if !zeroUpper56Bits(x.Args[i], depth-1) {
				return false
			}
		}
		return true

	}
	return false
}

// IsInLinableMove报告给定拱门是否执行给定大小的移动
// 。只有当用Move替换memmove是
// safe时，它才会返回true，这可能是因为Move很小，也可能是因为参数不相交。
// 这是用来检查是否将memmove替换为Move ops。
func isInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
	// 当memmove的参数不相交时，将其转换为Move总是安全的。
	// 大尺寸的移动操作可能会更快，也可能不会更快，这取决于平台
	// 降低它们的方式，因此我们只在我们知道
	// 具有快速移动操作的平台上执行此优化。
	switch c.arch {
	case "amd64":
		return sz <= 16 || (sz < 1024 && disjoint(dst, sz, src, sz))
	case "386", "arm64":
		return sz <= 8
	case "s390x", "ppc64", "ppc64le":
		return sz <= 8 || disjoint(dst, sz, src, sz)
	case "arm", "mips", "mips64", "mipsle", "mips64le":
		return sz <= 4
	}
	return false
}

// logLargeCopy记录大副本的发生。
// 最好的方法是在重写规则中，在这里可以很容易地找到移动的大小。
// /“大”任意选择为128字节；这可能会改变。
func logLargeCopy(v *Value, s int64) bool {
	if s < 128 {
		return true
	}
	if logopt.Enabled() {
		logopt.LogOpt(v.Pos, "copy", "lower", v.Block.Func.Name, fmt.Sprintf("%d bytes", s))
	}
	return true
}

// hasSmallRotate报告体系结构是否具有大小小于32位的旋转指令
// 。这用于决定是否促进某些旋转。
func hasSmallRotate(c *Config) bool {
	switch c.arch {
	case "amd64", "386":
		return true
	default:
		return false
	}
}

func newPPC64ShiftAuxInt(sh, mb, me, sz int64) int32 {
	if sh < 0 || sh >= sz {
		panic("PPC64 shift arg sh out of range")
	}
	if mb < 0 || mb >= sz {
		panic("PPC64 shift arg mb out of range")
	}
	if me < 0 || me >= sz {
		panic("PPC64 shift arg me out of range")
	}
	return int32(sh<<16 | mb<<8 | me)
}

func GetPPC64Shiftsh(auxint int64) int64 {
	return int64(int8(auxint >> 16))
}

func GetPPC64Shiftmb(auxint int64) int64 {
	return int64(int8(auxint >> 8))
}

func GetPPC64Shiftme(auxint int64) int64 {
	return int64(int8(auxint))
}

// 测试此值是否可以编码为rlwinm类
// 操作的掩码。口罩也可以从msb延伸到
// lsb。也就是说，有效掩码是32位字符串
// 的形式：0。。01..10..0或1。。10..01..1或1。。。1 
func isPPC64WordRotateMask(v64 int64) bool {
	// 分离最右边的1（如果没有0）并添加。
	v := uint32(v64)
	vp := (v & -v) + v
	// 同样适用于包装箱。
	vn := ^v
	vpn := (vn & -vn) + vn
	return (v&vp == 0 || vn&vpn == 0) && v != 0
}

// 压缩掩码并转换为单个值，格式为
// me | mb<<8 |旋转<<16 | nbits<<24，其中me和mb可用于重新生成输入掩码。
func encodePPC64RotateMask(rotate, mask, nbits int64) int64 {
	var mb, me, mbn, men int

	// 确定边界，然后对其进行解码
	if mask == 0 || ^mask == 0 || rotate >= nbits {
		panic("Invalid PPC64 rotate mask")
	} else if nbits == 32 {
		mb = bits.LeadingZeros32(uint32(mask))
		me = 32 - bits.TrailingZeros32(uint32(mask))
		mbn = bits.LeadingZeros32(^uint32(mask))
		men = 32 - bits.TrailingZeros32(^uint32(mask))
	} else {
		mb = bits.LeadingZeros64(uint64(mask))
		me = 64 - bits.TrailingZeros64(uint64(mask))
		mbn = bits.LeadingZeros64(^uint64(mask))
		men = 64 - bits.TrailingZeros64(^uint64(mask))
	}
	// 检查包装掩码（例如0和63位）
	if mb == 0 && me == int(nbits) {
		// 交换反向值
		mb, me = men, mbn
	}

	return int64(me) | int64(mb<<8) | int64(rotate<<16) | int64(nbits<<24)
}

// encodePPC64RotateMask的反向操作。返回为
// mb和me的值满足MASK（x，y）的幂ISA定义，其中MASK（mb，me）=MASK。
func DecodePPC64RotateMask(sauxint int64) (rotate, mb, me int64, mask uint64) {
	auxint := uint64(sauxint)
	rotate = int64((auxint >> 16) & 0xFF)
	mb = int64((auxint >> 8) & 0xFF)
	me = int64((auxint >> 0) & 0xFF)
	nbits := int64((auxint >> 24) & 0xFF)
	mask = ((1 << uint(nbits-mb)) - 1) ^ ((1 << uint(nbits-me)) - 1)
	if mb > me {
		mask = ^mask
	}
	if nbits == 32 {
		mask = uint64(uint32(mask))
	}

	// 让我符合ISA的定义。掩码（…，me）
	// 的第二个参数包含在内。
	me = (me - 1) & (nbits - 1)
	return
}

// 这验证掩码是一组
// 连续位，包括最少的
// 有效位。
func isPPC64ValidShiftMask(v int64) bool {
	if (v != 0) && ((v+1)&v) == 0 {
		return true
	}
	return false
}

func getPPC64ShiftMaskLength(v int64) int64 {
	return int64(bits.Len64(uint64(v)))
}

// 将右移分解为等效的旋转/遮罩、
// 和返回遮罩&m。
func mergePPC64RShiftMask(m, s, nbits int64) int64 {
	smask := uint64((1<<uint(nbits))-1) >> uint(s)
	return m & int64(smask)
}

// 将（ANDconst[m]（SRWconst[s]）合并为（RLWINM[y]），或返回0 
func mergePPC64AndSrwi(m, s int64) int64 {
	mask := mergePPC64RShiftMask(m, s, 32)
	if !isPPC64WordRotateMask(mask) {
		return 0
	}
	return encodePPC64RotateMask((32-s)&31, mask, 32)
}

// 测试输入CLRLLSLDI的右移是否可以合并为RLWINM。
// 返回编码的RLWINM常量，如果无法合并，则返回0。
func mergePPC64ClrlsldiSrw(sld, srw int64) int64 {
	mask_1 := uint64(0xFFFFFFFF >> uint(srw))
	// 对于CLRLDI，更方便的做法是将其视为掩码左位，然后向左旋转。
	mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))

	// 重写掩码以在最后一次左移后应用。
	mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))

	r_1 := 32 - srw
	r_2 := GetPPC64Shiftsh(sld)
	r_3 := (r_1 + r_2) & 31 // 这个可以打包。

	if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
		return 0
	}
	return encodePPC64RotateMask(int64(r_3), int64(mask_3), 32)
}

// 测试传入CLRLSLDI的RLWINM是否可以合并到RLWINM中。返回
// 编码的RLWINM常量，如果无法合并，则返回0。
func mergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
	r_1, _, _, mask_1 := DecodePPC64RotateMask(rlw)
	// 对于CLRLDI，更方便的做法是将其视为左位掩码，然后向左旋转。
	mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))

	// 组合遮罩，调整到最后的左移。
	mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(int64(sld)))
	r_2 := GetPPC64Shiftsh(int64(sld))
	r_3 := (r_1 + r_2) & 31 // 这个可以打包。

	// 验证结果是否仍然是小于等于32位的有效位掩码。
	if !isPPC64WordRotateMask(int64(mask_3)) || uint64(uint32(mask_3)) != mask_3 {
		return 0
	}
	return encodePPC64RotateMask(r_3, int64(mask_3), 32)
}

// 通过组合（SLDconst[sld]（SRWconst[srw]x））、
// 计算编码的RLWINM常量，如果无法组合，则返回0。
func mergePPC64SldiSrw(sld, srw int64) int64 {
	if sld > srw || srw >= 32 {
		return 0
	}
	mask_r := uint32(0xFFFFFFFF) >> uint(srw)
	mask_l := uint32(0xFFFFFFFF) >> uint(sld)
	mask := (mask_r & mask_l) << uint(sld)
	return encodePPC64RotateMask((32-srw+sld)&31, int64(mask), 32)
}

// 将一个32位常量值旋转另一个常量的便利函数。
func rotateLeft32(v, rotate int64) int64 {
	return int64(bits.RotateLeft32(uint32(v), int(rotate)))
}

func rotateRight64(v, rotate int64) int64 {
	return int64(bits.RotateLeft64(uint64(v), int(-rotate)))
}

// 将arm（64）位字段操作的lsb和宽度编码为预期的auxInt格式。
func armBFAuxInt(lsb, width int64) arm64BitField {
	if lsb < 0 || lsb > 63 {
		panic("ARM(64) bit field lsb constant out of range")
	}
	if width < 1 || lsb+width > 64 {
		panic("ARM(64) bit field width constant out of range")
	}
	return arm64BitField(width | lsb<<8)
}

// 返回arm64位字段ops的生长素字段的lsb部分。
func (bfc arm64BitField) getARM64BFlsb() int64 {
	return int64(uint64(bfc) >> 8)
}

// 返回arm64位字段ops的生长素字段的宽度部分。
func (bfc arm64BitField) getARM64BFwidth() int64 {
	return int64(bfc) & 0xff
}

// 检查在lsb上应用的掩码>>rshift是否是有效的arm64位字段操作掩码。
func isARM64BFMask(lsb, mask, rshift int64) bool {
	shiftedMask := int64(uint64(mask) >> uint64(rshift))
	return shiftedMask != 0 && isPowerOfTwo64(shiftedMask+1) && nto(shiftedMask)+lsb < 64
}

// 返回掩码的位域宽度>>arm64位域操作的rshift 
func arm64BFWidth(mask, rshift int64) int64 {
	shiftedMask := int64(uint64(mask) >> uint64(rshift))
	if shiftedMask == 0 {
		panic("ARM64 BF mask is zero")
	}
	return nto(shiftedMask)
}

// sizeof返回t的大小（字节）。
// 如果t不是a*类型，它会恐慌。类型
func sizeof(t interface{}) int64 {
	return t.(*types.Type).Size()
}

// registerizable报告t是否是适合
// 寄存器的基元类型。它假设float64值将始终适合于寄存器
// 即使严格来说这不是真的。
func registerizable(b *Block, typ *types.Type) bool {
	if typ.IsPtrShaped() || typ.IsFloat() {
		return true
	}
	if typ.IsInteger() {
		return typ.Size() <= b.Func.Config.RegSize
	}
	return false
}

// needRaceCleanup报告是否不需要调用racefuncenter/exit。
func needRaceCleanup(sym *AuxCall, v *Value) bool {
	f := v.Block.Func
	if !f.Config.Race {
		return false
	}
	if !isSameCall(sym, "runtime.racefuncenter") && !isSameCall(sym, "runtime.racefuncexit") {
		return false
	}
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			switch v.Op {
			case OpStaticCall, OpStaticLECall:
				// 检查racefuncenter将遇到racefunceit，反之亦然。
				// 允许呼叫惊慌*
				s := v.Aux.(*AuxCall).Fn.String()
				switch s {
				case "runtime.racefuncenter", "runtime.racefuncexit",
					"runtime.panicdivide", "runtime.panicwrap",
					"runtime.panicshift":
					continue
				}
				// 如果我们遇到任何呼叫，我们需要保持racefunc*、
				// 以获得准确的堆栈跟踪。
				return false
			case OpPanicBounds, OpPanicExtend:
				// 注意：这些是正常的紧急生成器（如上面的静态调用）。
			case OpClosureCall, OpInterCall, OpClosureLECall, OpInterLECall:
				// 如果有其他调用类型，我们必须保留race函数。
				return false
			}
		}
	}
	if isSameCall(sym, "runtime.racefuncenter") {
		// TODO寄存器ABI这需要清理。
		// 如果要删除racefuncenter，也要删除它的参数。
		if v.Args[0].Op != OpStore {
			if v.Op == OpStaticLECall {
				// 现在还没有商店。
				return true
			}
			return false
		}
		mem := v.Args[0].Args[2]
		v.Args[0].reset(OpCopy)
		v.Args[0].AddArg(mem)
	}
	return true
}

// symIsRO报告sym是否为只读全局。
func symIsRO(sym interface{}) bool {
	lsym := sym.(*obj.LSym)
	return lsym.Type == objabi.SRODATA && len(lsym.R) == 0
}

// symIsROZero报告sym是否为只读全局，其数据包含全零。
func symIsROZero(sym Sym) bool {
	lsym := sym.(*obj.LSym)
	if lsym.Type != objabi.SRODATA || len(lsym.R) != 0 {
		return false
	}
	for _, b := range lsym.P {
		if b != 0 {
			return false
		}
	}
	return true
}

// read8在offset off处从只读全局符号读取一个字节。
func read8(sym interface{}, off int64) uint8 {
	lsym := sym.(*obj.LSym)
	if off >= int64(len(lsym.P)) || off < 0 {
		// 全局符号的索引无效。
		// 这可能发生在死代码中，所以我们不想惊慌失措。
		// 只需返回任何值，它最终将被忽略。
		// 见第29215期。
		return 0
	}
	return lsym.P[off]
}

// read16在offset off处从只读全局符号读取两个字节。
func read16(sym interface{}, off int64, byteorder binary.ByteOrder) uint16 {
	lsym := sym.(*obj.LSym)
	// lsym。P写得很懒。
	// 在lsym结束后请求的字节数。P是0。
	var src []byte
	if 0 <= off && off < int64(len(lsym.P)) {
		src = lsym.P[off:]
	}
	buf := make([]byte, 2)
	copy(buf, src)
	return byteorder.Uint16(buf)
}

// read32在offset off处从只读全局符号读取四个字节。
func read32(sym interface{}, off int64, byteorder binary.ByteOrder) uint32 {
	lsym := sym.(*obj.LSym)
	var src []byte
	if 0 <= off && off < int64(len(lsym.P)) {
		src = lsym.P[off:]
	}
	buf := make([]byte, 4)
	copy(buf, src)
	return byteorder.Uint32(buf)
}

// read64在偏移量off处从只读全局符号读取八个字节。
func read64(sym interface{}, off int64, byteorder binary.ByteOrder) uint64 {
	lsym := sym.(*obj.LSym)
	var src []byte
	if 0 <= off && off < int64(len(lsym.P)) {
		src = lsym.P[off:]
	}
	buf := make([]byte, 8)
	copy(buf, src)
	return byteorder.Uint64(buf)
}

// sequentialAddresses如果能证明x+n==y 
func sequentialAddresses(x, y *Value, n int64) bool {
	if x.Op == Op386ADDL && y.Op == Op386LEAL1 && y.AuxInt == n && y.Aux == nil &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	if x.Op == Op386LEAL1 && y.Op == Op386LEAL1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	if x.Op == OpAMD64ADDQ && y.Op == OpAMD64LEAQ1 && y.AuxInt == n && y.Aux == nil &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	if x.Op == OpAMD64LEAQ1 && y.Op == OpAMD64LEAQ1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	return false
}

// flagConstant代表编译时比较的结果，则报告true。
// 这些标志的意义不一定代表硬件的标志寄存器的概念
// 这些只是编译时构造。
// 我们碰巧将这些语义与arm/arm64的语义相匹配。
// 请注意，这些语义与x86不同：进位标志与
// 减法的意义相反！
// 在amd64上，C=1表示借用，例如amd64上的SBB执行x-y-C。
// 在arm64上，C=0表示借用，例如arm64上的SBC执行x-y-^C。
// （因为它执行x+^y+C）。
// 见https:
type flagConstant uint8

// N报告操作结果是否为负（高位设置）。
func (fc flagConstant) N() bool {
	return fc&1 != 0
}

// Z报告操作的结果是否为0。
func (fc flagConstant) Z() bool {
	return fc&2 != 0
}

// C报告无符号加法是否溢出（进位），或无符号减法是否未下溢（借用）。
func (fc flagConstant) C() bool {
	return fc&4 != 0
}

// V报告签名的操作是否溢出或不足。
func (fc flagConstant) V() bool {
	return fc&8 != 0
}

func (fc flagConstant) eq() bool {
	return fc.Z()
}
func (fc flagConstant) ne() bool {
	return !fc.Z()
}
func (fc flagConstant) lt() bool {
	return fc.N() != fc.V()
}
func (fc flagConstant) le() bool {
	return fc.Z() || fc.lt()
}
func (fc flagConstant) gt() bool {
	return !fc.Z() && fc.ge()
}
func (fc flagConstant) ge() bool {
	return fc.N() == fc.V()
}
func (fc flagConstant) ult() bool {
	return !fc.C()
}
func (fc flagConstant) ule() bool {
	return fc.Z() || fc.ult()
}
func (fc flagConstant) ugt() bool {
	return !fc.Z() && fc.uge()
}
func (fc flagConstant) uge() bool {
	return fc.C()
}

func (fc flagConstant) ltNoov() bool {
	return fc.lt() && !fc.V()
}
func (fc flagConstant) leNoov() bool {
	return fc.le() && !fc.V()
}
func (fc flagConstant) gtNoov() bool {
	return fc.gt() && !fc.V()
}
func (fc flagConstant) geNoov() bool {
	return fc.ge() && !fc.V()
}

func (fc flagConstant) String() string {
	return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
}

type flagConstantBuilder struct {
	N bool
	Z bool
	C bool
	V bool
}

func (fcs flagConstantBuilder) encode() flagConstant {
	var fc flagConstant
	if fcs.N {
		fc |= 1
	}
	if fcs.Z {
		fc |= 2
	}
	if fcs.C {
		fc |= 4
	}
	if fcs.V {
		fc |= 8
	}
	return fc
}

// 注意：addFlags（x，y）！=子标签（x，-y）在某些情况下：
// -C标志的结果不同
// -当y==minint时，V标志的结果不同

// addFlags64返回将通过计算x+y设置的标志。
func addFlags64(x, y int64) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x+y == 0
	fcb.N = x+y < 0
	fcb.C = uint64(x+y) < uint64(x)
	fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
	return fcb.encode()
}

// subFlags64返回将通过计算x-y设置的标志。
func subFlags64(x, y int64) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x-y == 0
	fcb.N = x-y < 0
	fcb.C = uint64(y) <= uint64(x) // 手臂携带旗帜模型。
	fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
	return fcb.encode()
}

// addFlags32返回将通过计算x+y设置的标志。
func addFlags32(x, y int32) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x+y == 0
	fcb.N = x+y < 0
	fcb.C = uint32(x+y) < uint32(x)
	fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
	return fcb.encode()
}

// subFlags32返回将通过计算x-y设置的标志。
func subFlags32(x, y int32) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x-y == 0
	fcb.N = x-y < 0
	fcb.C = uint32(y) <= uint32(x) // 此代码遵循arm-carry标志模型。
	fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
	return fcb.encode()
}

// logicFlags64返回设置为x的符号/零的标志。
// C和V设置为false。
func logicFlags64(x int64) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x == 0
	fcb.N = x < 0
	return fcb.encode()
}

// logicFlags32返回设置为x的符号/零的标志。
// C和V设置为false。
func logicFlags32(x int32) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x == 0
	fcb.N = x < 0
	return fcb.encode()
}
